package com.niiwoo.civet.mobile.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Sets;
import com.niiwoo.activity.stage.dto.common.GiftSummarizeDTO;
import com.niiwoo.activity.stage.dto.request.goods.SummarizeListRequestDTO;
import com.niiwoo.activity.stage.dto.response.channel.DraingeChannelQueryRespDTO;
import com.niiwoo.activity.stage.dto.response.goods.SummarizeListResponseDTO;
import com.niiwoo.activity.stage.dto.response.invite.InviteInviteeSummaryRespDTO;
import com.niiwoo.activity.stage.dto.response.invite.InviteMoneySummaryRespDTO;
import com.niiwoo.activity.stage.dto.response.notice.NoviceTaskStatusRespDTO;
import com.niiwoo.activity.stage.enums.goods.GoodsTypeDicEnum;
import com.niiwoo.activity.stage.service.channel.DraingeChannelDubboService;
import com.niiwoo.activity.stage.service.goods.GiftDubboService;
import com.niiwoo.activity.stage.service.invite.InviterDetailDubboService;
import com.niiwoo.activity.stage.service.notice.HomePageAppDubboService;
import com.niiwoo.civet.account.constant.AccountRegisterErrorCode;
import com.niiwoo.civet.account.dto.common.BankCardDTO;
import com.niiwoo.civet.account.dto.common.UserAccountInfoDTO;
import com.niiwoo.civet.account.dto.request.QueryMoneyTotalRequestDTO;
import com.niiwoo.civet.account.dto.request.StatisticUserBillAmountRequestDTO;
import com.niiwoo.civet.account.dto.response.AccountBaseResponse;
import com.niiwoo.civet.account.dto.response.QueryMoneyTotalResponseDTO;
import com.niiwoo.civet.account.dto.response.StatisticUserBillAmountReponseDTO;
import com.niiwoo.civet.account.dto.response.WithholdProtocolResultDTO;
import com.niiwoo.civet.account.enums.AccountActiveEnum;
import com.niiwoo.civet.account.enums.BillAmountStatisticsEnum;
import com.niiwoo.civet.account.service.AccountDubboService;
import com.niiwoo.civet.account.service.AccountRegisterDubboService;
import com.niiwoo.civet.account.service.MoneyTotalDubboService;
import com.niiwoo.civet.account.service.bankcard.BankCardDubboService;
import com.niiwoo.civet.account.service.bill.UserBillStatisticsDubboService;
import com.niiwoo.civet.account.service.withholdProtocol.WithholdProtocolDubboService;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.civet.mobile.util.ParameterValidator;
import com.niiwoo.civet.mobile.util.R360RedisService;
import com.niiwoo.civet.mobile.vo.request.BankAccountInfoRequestVO;
import com.niiwoo.civet.mobile.vo.request.HeadImageRequestVO;
import com.niiwoo.civet.mobile.vo.request.TradePwdResetPrepareH5RequestVO;
import com.niiwoo.civet.mobile.vo.request.TradePwdResetPrepareRequestVO;
import com.niiwoo.civet.mobile.vo.request.user.*;
import com.niiwoo.civet.mobile.vo.response.BankAccountInfoVO;
import com.niiwoo.civet.mobile.vo.response.IsChangeMobileNoResponseVO;
import com.niiwoo.civet.mobile.vo.response.TradePwdResetPrepareResponseVO;
import com.niiwoo.civet.mobile.vo.response.user.*;
import com.niiwoo.civet.trade.constant.TradeRedisKey;
import com.niiwoo.civet.trade.dto.common.InvestEvaluationDTO;
import com.niiwoo.civet.trade.dto.request.InvestAmountStatisticsRequestDTO;
import com.niiwoo.civet.trade.dto.request.guarantee.GuaranteeRequestDTO;
import com.niiwoo.civet.trade.dto.response.InvestAmountStatisticsResponseDTO;
import com.niiwoo.civet.trade.dto.response.UserAutoInvestConfigDTO;
import com.niiwoo.civet.trade.dto.response.guarantee.GuaranteeResponseDTO;
import com.niiwoo.civet.trade.dto.response.myloan.LoanIndexQueryResponseDTO;
import com.niiwoo.civet.trade.enums.GuaranteeTypeEnum;
import com.niiwoo.civet.trade.enums.ProjectStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectSubStatusEnum;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.civet.trade.service.guarantee.GuaranteeDubboService;
import com.niiwoo.civet.trade.service.invest.AutoInvestDubboService;
import com.niiwoo.civet.trade.service.invest.InvestDubboService;
import com.niiwoo.civet.trade.service.invest.InvestOrderDubboService;
import com.niiwoo.civet.trade.service.loan.SpeedLoanDubboService;
import com.niiwoo.civet.trade.service.myloan.MyLoanDubboService;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.civet.user.constants.ChangeMobilePromptMessage;
import com.niiwoo.civet.user.constants.LoginAccountErrorCode;
import com.niiwoo.civet.user.dto.request.*;
import com.niiwoo.civet.user.dto.response.*;
import com.niiwoo.civet.user.enums.*;
import com.niiwoo.civet.user.service.*;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.base.helper.StringHelper;
import com.niiwoo.tripod.base.plan.support.AmountHandleConstant;
import com.niiwoo.tripod.consumer.component.FileUploadHandler;
import com.niiwoo.tripod.consumer.properties.FileUploadProperties;
import com.niiwoo.tripod.consumer.util.EmojiFilter;
import com.niiwoo.tripod.consumer.util.FileMediaExtensions;
import com.niiwoo.tripod.consumer.util.ImageUploadUtil;
import com.niiwoo.tripod.lanmao.component.LanMaoGatewayService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.UserAuthorizationEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.enums.UserTypeEnum;
import com.niiwoo.tripod.lanmao.request.ChangeBankCardMobileNoRequest;
import com.niiwoo.tripod.lanmao.request.ChangeTradePasswordRequest;
import com.niiwoo.tripod.lanmao.request.UserAuthorizationRequest;
import com.niiwoo.tripod.lanmao.response.LanMaoGatewayDTO;
import com.niiwoo.tripod.provider.dto.response.PageResponseDTO;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.tiancheng.request.afp.AgainstFakeCallbackRequest;
import com.niiwoo.tripod.web.annotation.AuthIgnore;
import com.niiwoo.tripod.web.properties.ShiroProperties;
import com.niiwoo.tripod.web.util.PrincipalContext;
import com.niiwoo.tripod.web.vo.Empty;
import com.niiwoo.tripod.web.vo.PageRequestVO;
import com.niiwoo.tripod.web.vo.PageResponseVO;
import com.niiwoo.tripod.web.vo.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Slf4j
@RestController
@RequestMapping("/userBasic")
@Api(tags = "用户基础信息", description = "/userBasic")
public class UserBasicController extends BaseController {

    @Reference(version = "1.0.0")
    private UserBasicInfoDubboService userBasicInfoDubboService;
    @Reference(version = "1.0.0")
    private UserLoginAccountDubboService userLoginAccountService;
    @Reference(version = "1.0.0")
    private AccountDubboService accountDubboService;
    @Reference(version = "1.0.0")
    private UserSMSDubboService UserSMSService;
    @Reference(version = "1.0.0")
    private MoneyTotalDubboService moneyTotalDubboService;
    @Reference(version = "1.0.0")
    private UserLoginAccountDubboService userLoginAccountDubboService;
    @Reference(version = "1.0.0")
    private AutoInvestDubboService autoInvestDubboService;
    @Reference(version = "1.0.0")
    private InvestDubboService investDubboService;
    @Reference(version = "1.0.0")
    private UserStatusDubboService userStatusDubboService;
    @Reference(version = "1.0.0")
    private SpeedLoanDubboService speedLoanDubboService;
    @Reference(version = "1.0.0")
    private MyLoanDubboService myLoanDubboService;
    @Reference(version = "1.0.0")
    private BankCardDubboService bankCardDubboService;
    @Reference(version = "1.0.0")
    private DraingeChannelDubboService draingeChannelDubboService;
    @Reference(version = "1.0.0")
    private AccountRegisterDubboService accountRegisterService;
    @Reference(version = "1.0.0")
    private GuaranteeDubboService guaranteeDubboService;
    @Reference(version = "1.0.0")
    private UserIdentityDubboService userIdentityDubboService;
    @Reference(version = "1.0.0")
    private ProjectDubboService projectDubboService;
    @Reference(version = "1.0.0")
    private MobileChangeRecordDubboService mobileChangeRecordDubboService;
    @Reference(version = "1.0.0")
    private UserDataDubboService userDataDubboService;

    @Reference(version = "1.0.0")
    private WithholdProtocolDubboService withholdProtocolDubboService;
    @Reference(version = "1.0.0")
    private UserAccountDubboService userAccountDubboService;
    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;
    @Reference(version = "1.0.0")
    private InviterDetailDubboService inviterDetailDubboService;
    @Reference(version = "1.0.0")
    private GiftDubboService giftDubboService;

    @Reference(version = "1.0.0")
    private InvestOrderDubboService investOrderDubboService;

    @Reference(version = "1.0.0")
    private HomePageAppDubboService homePageAppDubboService;

    @Autowired
    private FileUploadHandler fileUploadHandler;
    @Autowired
    private ShiroProperties shiroProperties;
    @Autowired
    private PrivacyMasks privacyMasks;
    @Autowired
    private LanMaoGatewayService lanMaoGatewayService;
    @Autowired
    private LanMaoSequence lanMaoSequence;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private R360RedisService r360RedisService;

    @Reference(version = "1.0.0")
    private OrganizationDubboService organizationDubboService;

    @Reference(version = "1.0.0")
    private UserBillStatisticsDubboService userBillStatisticsDubboService;

    @Value("${online_time_for_creditor}")
    private String onlineTime;

    @ApiOperation(value = "获取用户基础信息(黄敏)")
    @PostMapping("/getUserBasicInfo")
    public Result<UserBasicInfoResponseVO> getUserBasicInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());

        UserBasicInfoResponseDTO responseDTO = userBasicInfoDubboService.getUserBasicInfo(userId);
        InvestEvaluationDTO investEvaluationDTO=investDubboService.getInvestEvaluationInfo(userId);
        Future<AccountBaseResponse> accountFuture = RpcContext.getContext().asyncCall(() -> accountDubboService.getNiiwooAccount(userId, UserRoleEnum.INVESTOR));
        UserBasicInfoResponseVO responseVO = new UserBasicInfoResponseVO();
        responseVO.setEvaluationLevel(investEvaluationDTO.getHadEvaluate()==0 ? 0: investEvaluationDTO.getLevel());
        responseVO.setUserId(responseDTO.getUserId());
        responseVO.setNickName(responseDTO.getNickName());
        responseVO.setGender(responseDTO.getGender());
        responseVO.setNiiwooCode(responseDTO.getNiiwooCode());
        responseVO.setNiiwooScore(responseDTO.getNiiwooScore());
        responseVO.setHeadImage(responseDTO.getHeadImage());
        responseVO.setMobileNo(responseDTO.getMobileNo());
        responseVO.setPersonalSign(responseDTO.getPersonalSign());
        responseVO.setIdentityTag(responseDTO.getIdentityTag());
        responseVO.setNiiwooFlag(responseDTO.getNiiwooFlag());
        responseVO.setRegisterChannel(responseDTO.getRegisterChannel());
        responseVO.setWindowFlag(DrainageChannelsEnum.IsShowWindow.CLOSE_WINDOW.getValue());
        List<AccountBaseResponse> accountBaseResponseList = Optional.ofNullable(accountDubboService.listNiiwooAccountByUserId(userId)).orElse(Collections.EMPTY_LIST);
        int bd = accountBaseResponseList.stream()
                .filter(a ->
                        a.getImportUserActiva().equals(AccountActiveEnum.ACTIVATED.getValue()) &&
                                a.getAccountRole().equals(UserRoleEnum.BORROWERS.getValue())
                )
                .findFirst()
                .map(a -> 1)
                .orElse(0);
        int bi = accountBaseResponseList.stream()
                .filter(a ->
                        a.getImportUserActiva().equals(AccountActiveEnum.ACTIVATED.getValue()) &&
                                a.getAccountRole().equals(UserRoleEnum.INVESTOR.getValue())
                )
                .findFirst()
                .map(a -> 2)
                .orElse(0);
        responseVO.setCityName(responseDTO.getCityName());
        responseVO.setProvinceName(responseDTO.getProvinceName());
        responseVO.setDepositInfo(bd + bi);
        //H5注册首次登录弹窗(注册类型为：第三方渠道 或 广告投放渠道 弹出提示框)
        if (responseDTO.getWindowFlag() == null || DrainageChannelsEnum.IsShowWindow.CLOSE_WINDOW.getValue().equals(responseDTO.getWindowFlag())) {
            DraingeChannelQueryRespDTO respDTO = null;
            try {
                respDTO = draingeChannelDubboService.selectByUserId(userId);
                log.info("获取用户注册渠道信息###userId={},respDTO={}", userId, JSON.toJSONString(respDTO));
            } catch (Exception e) {
                log.error("获取用户注册渠道信息异常###userId={},respDTO={}", userId, JSON.toJSONString(respDTO));
            }
            if (respDTO != null && (DrainageChannelsEnum.ADVERTISING_CHANNELS.getType().equals(respDTO.getChannelType())
                    || DrainageChannelsEnum.THIRD_PARTY_CHANNELS.getType().equals(respDTO.getChannelType()))) {
                responseVO.setWindowFlag(DrainageChannelsEnum.IsShowWindow.OPEN_WINDOW.getValue());
            }
        }
        //获取用户是否开启免密投资
        try {
            AccountBaseResponse accountInfo = accountFuture.get();
            if (accountInfo == null) {
                responseVO.setIsFreeInvest(Byte.valueOf("0"));
            } else {
                responseVO.setIsFreeInvest(accountInfo.getTender());
            }
        } catch (InterruptedException e) {
            log.error("用户基础信息###查询免密投资###异常", e);
        } catch (ExecutionException e) {
            log.error("用户基础信息###查询免密投资###异常", e);
        }
        return Result.with(responseVO);
    }

    @ApiOperation(value = "H5引流弹窗通知(黄敏)")
    @PostMapping("/showWindowCallback")
    public Empty showWindowCallback() {
        String userId = String.valueOf(PrincipalContext.getUserId());

        //修改H5引流弹窗通知为：1 已通知
        userBasicInfoDubboService.showWindowCallback(userId);
        return Empty.getInstance();
    }

    @ApiOperation(value = "修改用户昵称(黄敏)")
    @PostMapping("/updateUserNickName")
    public Empty updateUserNickName(@RequestBody @Valid UpdateNickNameRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());

        //判断昵称,修改场景类型
        if (StringUtils.isAllBlank(requestVO.getNickName(), requestVO.getUpdateType())) {
            throw new BizException("USR10015");
        }
        //过滤Emoji表情
        String nickName = EmojiFilter.filterEmoji(requestVO.getNickName());
        UserBasicInfoRequestDTO userBasicInfoRequestDTO = new UserBasicInfoRequestDTO();
        userBasicInfoRequestDTO.setUserId(userId);
        userBasicInfoRequestDTO.setUpdateType(requestVO.getUpdateType());
        userBasicInfoRequestDTO.setNickName(nickName);
        userBasicInfoDubboService.updateUserNickName(userBasicInfoRequestDTO, requestVO.getNickName());
        return Empty.getInstance();
    }

    @ApiOperation(value = "昵称修改状态(黄敏)")
    @PostMapping("/updateUserNickNameState")
    public Result<UserNickNameStateResponseVO> updateUserNickNameState() {
        String userId = String.valueOf(PrincipalContext.getUserId());

        UserNickNameStateResponseVO responseVO = new UserNickNameStateResponseVO();
        Date nickNameModifyTime = userBasicInfoDubboService.updateUserNickNameState(userId);
        if (nickNameModifyTime == null) {
            responseVO.setIsModify(Byte.valueOf("1")); //昵称是否可以修改(0.不可以 1.可以)
        } else {
            DateTime updateTime = new DateTime(nickNameModifyTime).plusDays(180); //180天后可以修改昵称
            responseVO.setUpdateDate(updateTime.toDate());
            if (updateTime.isBeforeNow()) {
                responseVO.setIsModify(Byte.valueOf("1"));
            } else {
                responseVO.setIsModify(Byte.valueOf("0"));
            }
        }
        return Result.with(responseVO);
    }

    @ApiOperation(value = "修改用户个性签名(黄敏)")
    @PostMapping("/updateUserPersonalSign")
    public Empty updateUserPersonalSign(@RequestBody UpdatePersonalSignRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());

        //过滤Emoji表情
        String personalSign = EmojiFilter.filterEmoji(requestVO.getPersonalSign());
        UserBasicInfoRequestDTO userBasicInfoRequestDTO = new UserBasicInfoRequestDTO();
        userBasicInfoRequestDTO.setUserId(userId);
        userBasicInfoRequestDTO.setPersonalSign(personalSign);
        userBasicInfoDubboService.updateUserPersonalSign(userBasicInfoRequestDTO);
        return Empty.getInstance();
    }


    @ApiOperation(value = "修改用户头像(黄敏)")
    @PostMapping("/headImage")
    public Result<HeadImageResponseVO> saveHeadImage(@RequestBody @Valid HeadImageRequestVO headImageRequestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());

        HeadImageResponseVO responseVO = new HeadImageResponseVO();
        FileUploadProperties.FileUploadResult headImage;
        if (!fileUploadHandler.checkImageUploadMaxSize(headImageRequestVO.getHeadImage())) {
            log.error("图片大小不能超过5M：{}" + headImageRequestVO.getHeadImage());
            throw new BizException("USR10017");
        }
        if (!ImageUploadUtil.checkType(FileMediaExtensions.parseMediaExtension(headImageRequestVO.getHeadImage()))) {
            headImage = fileUploadHandler.upload(headImageRequestVO.getHeadImage(), true, "jpg");
        } else {
            headImage = fileUploadHandler.upload(headImageRequestVO.getHeadImage(), true);
        }
        responseVO.setHeadImage(headImage.getImageUrl());
        UserBasicInfoRequestDTO userBasicInfoRequestDTO = new UserBasicInfoRequestDTO();
        userBasicInfoRequestDTO.setUserId(userId);
        userBasicInfoRequestDTO.setHeadImage(responseVO.getHeadImage());
        userBasicInfoDubboService.updateHeadImage(userBasicInfoRequestDTO);
        return Result.with(responseVO);
    }

    @ApiOperation(value = "你我分详情查询(黄敏)")
    @PostMapping("/getNiiwooScoreDetail")
    public Result<NiiwooScoreDetailResponseVO> niiwooScoreDetail() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("你我分详情查询###userId={}",userId);

        NiiwooScoreDetailResponseVO responseVO = new NiiwooScoreDetailResponseVO();
        NiiwooScoreDetailResponseVO.RadarDetails radarDetails = new NiiwooScoreDetailResponseVO.RadarDetails();
        NiiwooScoreResponseDTO responseDTO = userBasicInfoDubboService.selectUserNiiwooScore(userId);
        responseVO.setScore(responseDTO.getScore());
        responseVO.setScoreLevel(responseDTO.getScoreLevel());
        responseVO.setEvaluateTime(responseDTO.getEvaluateTime());
        JSONObject radarDetailsJson = (JSONObject) JSONObject.parse(responseDTO.getScoreDetail());
        //天称推送过来的变量名
        radarDetails.setBehavior(radarDetailsJson.get("Behavior").toString());
        radarDetails.setCreditHistory(radarDetailsJson.get("CreditHistory").toString());
        radarDetails.setEngagementAbility(radarDetailsJson.get("EngagementAbility").toString());
        radarDetails.setGuanXi(radarDetailsJson.get("GuanXi").toString());
        radarDetails.setIdFeature(radarDetailsJson.get("IdFeature").toString());
        responseVO.setRadarDetails(radarDetails);
        return Result.with(responseVO);
    }

    @ApiOperation(value = "你我分更新记录查询(黄敏)")
    @PostMapping("/niiwooScoreRecordList")
    public Result<PageResponseVO> niiwooScoreRecordList(@RequestBody @Valid PageRequestVO pageRequestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());

        NiiwooScorePageRequestDTO niiwooScorePageRequestDTO = new NiiwooScorePageRequestDTO();
        niiwooScorePageRequestDTO.setUserId(userId);
        niiwooScorePageRequestDTO.setPageNumber(pageRequestVO.getPageNumber());
        niiwooScorePageRequestDTO.setPageSize(pageRequestVO.getPageSize());
        PageResponseDTO pageResponseDTO = userBasicInfoDubboService.selectNiwoScoreRecordListByPage(niiwooScorePageRequestDTO);
        PageResponseVO pageResponseVO = new PageResponseVO();
        pageResponseVO.setItems(pageResponseDTO.getItems());
        pageResponseVO.setTotalCount(pageResponseDTO.getTotalCount());
        pageResponseVO.setTotalPage(pageResponseDTO.getTotalPage());
        return Result.with(pageResponseVO);
    }

    @AuthIgnore
    @ApiOperation(value = "天秤调用批量保存你我分(黄敏)")
    @PostMapping("/batchSaveNiiwooScore")
    public String batchSaveNiiWooScore(HttpServletRequest servletRequest) {
        AgainstFakeCallbackRequest callbackResponse = new AgainstFakeCallbackRequest();
        String niiWooScore = servletRequest.getParameter("jsonString");
        if (StringUtils.isEmpty(niiWooScore)) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("请求参数错误");
            return JSON.toJSONString(niiWooScore);
        }
        SaveNiiWooScoreRequestVO niWoScoreList = JSON.parseObject(niiWooScore, SaveNiiWooScoreRequestVO.class);
        if (niWoScoreList.getNiWoScoreList().size() <= 0) {
            callbackResponse.setResult("0");
            callbackResponse.setMessage("请求参数为空");
            return JSON.toJSONString(callbackResponse);
        }
        JSONArray jsonArray = new JSONArray();
        for (SaveNiiWooScoreRequestVO.NiWoScore requestVO : niWoScoreList.getNiWoScoreList()) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userId", requestVO.getUserId());
            jsonObject.put("niwoScore", requestVO.getNiWoScore());
            JSONObject radarDetails = new JSONObject();
            radarDetails.put("IdFeature", requestVO.getRadarDetails().getIdFeature());
            radarDetails.put("CreditHistory", requestVO.getRadarDetails().getCreditHistory());
            radarDetails.put("Behavior", requestVO.getRadarDetails().getBehavior());
            radarDetails.put("EngagementAbility", requestVO.getRadarDetails().getEngagementAbility());
            radarDetails.put("GuanXi", requestVO.getRadarDetails().getGuanXi());
            jsonObject.put("radarDetails", radarDetails);
            jsonArray.add(jsonObject);
        }
        int totalCount = userBasicInfoDubboService.insertBatchNiwoScore(jsonArray);
        callbackResponse.setResult("1");
        callbackResponse.setMessage("操作成功");
        callbackResponse.setTotalCount(totalCount);
        callbackResponse.setData(new AgainstFakeCallbackRequest.DataInfo());
        return JSON.toJSONString(callbackResponse);
    }


    @ApiOperation(value = "发送短信验证码(黄斌)")
    @RequestMapping(path = "/sms", method = RequestMethod.POST)
    @AuthIgnore
    public Empty sendSMS(@RequestBody @Valid UserSMSRequestVO request) {
        UserSMSTypeEnum smsType = UserSMSTypeEnum.of(request.getBizType().byteValue());
        if (smsType == null) {
            throw new BizException(LoginAccountErrorCode.UNKNOWN_SMS_TYPE);
        }
        RefreshSMSCodeRequestDTO refreshSMSCodeRequestDTO = new RefreshSMSCodeRequestDTO();
        refreshSMSCodeRequestDTO.setSmsType(smsType);
        refreshSMSCodeRequestDTO.setLoginMobileNo(request.getLoginMobileNo());
        if (!UserSMSService.createSMS(refreshSMSCodeRequestDTO)) {
            throw new BizException(LoginAccountErrorCode.SMS_SEND_FAIL);
        }
        return Empty.getInstance();
    }

    @ApiOperation(value = "通过短信重置登录密码(黄斌)")
    @RequestMapping(path = "/loginPwdSMSReset", method = RequestMethod.POST)
    @AuthIgnore
    public Empty resetLoginPwdBySMSCode(@RequestBody @Valid ResetLoginPasswordRequestVO vo) {
        if (!ParameterValidator.valid(vo.getPassword())) {
            throw new BizException(LoginAccountErrorCode.PASSWORD_FORMAT_ERROR);
        }
        if (StringUtils.isBlank(vo.getLoginMobileNo()) || !ParameterValidator.isMobileNo(vo.getLoginMobileNo())) {
            throw new BizException(LoginAccountErrorCode.LOGIN_MOBILENO_FORMAT_ERROR);
        }
        ResetLoginPasswordRequestDTO dto = new ResetLoginPasswordRequestDTO();
        dto.setLoginMobileNo(vo.getLoginMobileNo());
        dto.setSmsCode(vo.getSmsCode());
        dto.setSalt(getRandomSalt());
        dto.setPassword(getPasswordHash(vo.getPassword(), dto.getSalt()));
        if (!userLoginAccountService.resetLoginPasswordBySMS(dto)) {
            throw new BizException(LoginAccountErrorCode.RESET_LOGIN_PASSWORD_FAIL);
        }
        return Empty.getInstance();
    }


    @ApiOperation(value = "通过旧密码重置登录密码(黄敏)")
    @RequestMapping(path = "/loginPwdSelfReset", method = RequestMethod.POST)
    public Empty resetLoginPwdByOldOne(@RequestBody @Valid LoginPwdSelfResetPwdRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());

        if (!ParameterValidator.valid(requestVO.getNewPassword())) {
            throw new BizException(LoginAccountErrorCode.PASSWORD_FORMAT_ERROR);
        }
        if (!requestVO.getNewPassword().equals(requestVO.getNewPasswordTwice())) {
            throw new BizException("USR10025");
        }
        LoginAccountResponseDTO responseDTO = userLoginAccountDubboService.getLoginAccount(userId);
        String password = getPasswordHash(requestVO.getOldPassword(), responseDTO.getSlat());
        if (!password.equals(responseDTO.getPassword())) {
            throw new BizException("USR10026");
        }
        LoginPwdSelfResetPwdRequestDTO requestDTO = new LoginPwdSelfResetPwdRequestDTO();
        requestDTO.setUserId(userId);
        requestDTO.setSlat(getRandomSalt());
        requestDTO.setNewPassword(getPasswordHash(requestVO.getNewPassword(), requestDTO.getSlat()));
        userLoginAccountService.resetLoginPwdByOldOne(requestDTO);
        return Empty.getInstance();
    }


    /**
     * 获取密码哈希值
     *
     * @param password 密码明文
     * @param salt     盐值
     * @return 密码哈希值
     */
    private String getPasswordHash(String password, String salt) {
        ShiroProperties.HashedCredentialProperties hashedCredential = shiroProperties.getHashedCredential();
        return new SimpleHash(hashedCredential.getHashAlgorithName(), ParameterValidator.toTuanDaiPassword(password), salt, hashedCredential.getHashIterations()).toString();
    }

    /**
     * 获取随机盐值
     *
     * @return 盐值
     */
    private String getRandomSalt() {
        return StringHelper.genRandomStr(5);
    }

    @PostMapping("/myselfIndex")
    @ApiOperation("我-首页数据(宾村)")
    public Result<MyselfIndexResponseVO> getMyselfData() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        MyselfIndexResponseVO responseVO = new MyselfIndexResponseVO();
        DecimalFormat df = new DecimalFormat("#,##0.00");
        log.info("我-首页数据userId{}", userId);
        Future<MyPageUserInfoDTO> myPageUserfuture = RpcContext.getContext().asyncCall(() -> {
            log.info("--MyPageUserInfoDTO.call()----");
            return userBasicInfoDubboService.getMyPageUserInfo(userId);
        });
        Future<UserAccountInfoDTO> userAccInfoDTOFuture = RpcContext.getContext().asyncCall(() -> {
            log.info("--UserAccountInfoDTO.call()----");
            return accountDubboService.queryNiiwooAccountFlat(userId);
        });
        Future<UserAutoInvestConfigDTO> autoInvestConfigFuture = RpcContext.getContext().asyncCall(() -> {
            log.info("--UserAutoInvestConfigDTO.call()----");
            return autoInvestDubboService.queryUserAutoInvestConfig(userId);
        });
        //
        Future<Integer> borrowNum = RpcContext.getContext().asyncCall(() ->{
        	return projectDubboService.queryProjectCountByUserId(userId);
        });
        //本月应还
        Future<LoanIndexQueryResponseDTO> loanIndexQueryFuture = RpcContext.getContext().asyncCall(() ->{
        	return myLoanDubboService.loanIndexQuery(userId);
        });
        //新手任务
        Future<NoviceTaskStatusRespDTO> noviceTask =   RpcContext.getContext().asyncCall(() ->{
        	return homePageAppDubboService.getNoviceTaskStatus(userId);
          });
        StatisticUserBillAmountRequestDTO statisticUserBillAmountRequestDTO = new StatisticUserBillAmountRequestDTO();
		List<BillAmountStatisticsEnum> billAmountStatisticsEnums = Arrays.asList(
				BillAmountStatisticsEnum.ACCUMULATED_PROFIT);
		statisticUserBillAmountRequestDTO.setUserId(userId);
		statisticUserBillAmountRequestDTO.setBillAmountStatisticsEnums(billAmountStatisticsEnums);
        //累计收益
        Future<List<StatisticUserBillAmountReponseDTO>> receivedStatisticFuture = RpcContext.getContext().asyncCall(() -> userBillStatisticsDubboService.statisticUserBillAmounts(statisticUserBillAmountRequestDTO));
        Future<GuaranteeResponseDTO> guaranteeResponseFuture = RpcContext.getContext().asyncCall(() -> {
            GuaranteeRequestDTO requestDTO = new GuaranteeRequestDTO();
            requestDTO.setUserId(userId);
            requestDTO.setType(GuaranteeTypeEnum.CREDIT_LOAN);
            log.info("--GuaranteeResponseDTO.call()----");
            return guaranteeDubboService.queryTotalGuaranteeNum(requestDTO);
        });

        InvestAmountStatisticsRequestDTO investAmountStatisticsRequestDTO = new InvestAmountStatisticsRequestDTO();
        investAmountStatisticsRequestDTO.setUserId(userId);
        investAmountStatisticsRequestDTO.setQueryType(Byte.valueOf("0"));
        Future<InvestAmountStatisticsResponseDTO> dueInFuture = RpcContext.getContext().asyncCall(() -> investOrderDubboService.myInvestAmountStatistics(investAmountStatisticsRequestDTO));

        // 5.5.0  取消显示我的礼品小红点
        // log.info("--isExistOverdueAndRepaymentProject.call()----");
        // int overdueAndRepaymentProjectCount =  myLoanDubboService.isExistOverdueAndRepaymentProject(userId);
        // log.info("--isExistOverdueAndRepaymentProject.overdueAndRepaymentProjectCount={}",overdueAndRepaymentProjectCount);

        try {
            //取用户基本信息
            MyPageUserInfoDTO myPageUserInfoDTO = myPageUserfuture.get();
            BeanUtils.copyProperties(myPageUserInfoDTO, responseVO);
            if(Objects.nonNull(myPageUserInfoDTO)&&Byte.valueOf("2").equals(myPageUserInfoDTO.getUserSeletctInvestLoanTag())) {
            	responseVO.setShowBorrowLabel(Byte.valueOf("1"));
            }
            log.info("用户基本信息{}", JSON.toJSONString(myPageUserInfoDTO));
            //取账户信息
            UserAccountInfoDTO dto = userAccInfoDTOFuture.get();
            BeanUtils.copyProperties(dto, responseVO);
            log.info("账户信息{}", JSON.toJSONString(dto));
            responseVO.setBalanceAmount(dto.getBalanceAmountTotal());
            responseVO.setIsFreeInvest(dto.getIsFreeInvest());
            if(Objects.nonNull(dto.getAccountIdBorrower())) {
            	responseVO.setShowBorrowLabel(Byte.valueOf("1"));
            }else {
            	Integer num =borrowNum.get();
            	if(Objects.nonNull(num)&&num>0) {
            		responseVO.setShowBorrowLabel(Byte.valueOf("1"));
            	}
            }
            //用户财富
            QueryMoneyTotalRequestDTO queryMoneyTotalRequestDTO = new QueryMoneyTotalRequestDTO();
            queryMoneyTotalRequestDTO.setUserId(userId);
            QueryMoneyTotalResponseDTO queryMoneyTotalResponseDTO = moneyTotalDubboService.queryMoneyTotal(queryMoneyTotalRequestDTO);

            InvestAmountStatisticsResponseDTO dueIn = dueInFuture.get();
            BigDecimal dueInCorpusInterest = dueIn.getDueInCorpusInterest();
            //待收本息
            responseVO.setDueInCorpusInterest(dueInCorpusInterest);
            //今日待收
            if(Objects.nonNull(dueIn.getTodayReceivable())&&BigDecimal.ZERO.compareTo(dueIn.getTodayReceivable())<0) {
            	responseVO.setTodayReceivable("今日待收本息"+df.format(dueIn.getTodayReceivable())+"元");
            }

            // 财富总额(可用余额[投资账户余额+借款账户余额]+在途资金 + 待收本息)
            responseVO.setWealthAmountTotal(queryMoneyTotalResponseDTO.getInvestorAvailableBalance().add(queryMoneyTotalResponseDTO.getBorrowerAvailableBalance())
                    .add(queryMoneyTotalResponseDTO.getOnWayAmount()).add(dueInCorpusInterest));

            UserAutoInvestConfigDTO userAutoInvestConfigDTO = autoInvestConfigFuture.get();
            if (userAutoInvestConfigDTO != null && userAutoInvestConfigDTO.getUserConfig() != null) {
            	Byte enable = userAutoInvestConfigDTO.getUserConfig().getEnabled();
            	//关闭状态并且用户有配置的为历史开启过 
            	if(Byte.valueOf("0").equals(enable)&&Byte.valueOf("0").equals(userAutoInvestConfigDTO.getEnabledSystem())) {
            		responseVO.setIsOpenAutoInvest(Byte.valueOf("2"));
            	}else {
            		responseVO.setIsOpenAutoInvest(enable);
            	}
                
            }

            // responseVO.setBorrowTip(overdueAndRepaymentProjectCount > 0 ? (byte)1 : (byte)0);
            GuaranteeResponseDTO guaranteeResponseDTO = guaranteeResponseFuture.get();
            responseVO.setGuaranteeRecordNum(guaranteeResponseDTO.isSuccess() ? guaranteeResponseDTO.getTotalGuaranteeNum() : 0);

            NoviceTaskStatusRespDTO noviceTaskResult =   noviceTask.get();
            if(Objects.nonNull(noviceTaskResult)) {
            	responseVO.setIsShowUpdateImg(noviceTaskResult.getIsFristSettingImage());
            	responseVO.setIsShowUpdateNickName(noviceTaskResult.getIsFristSettingNickName());
            }
            //累计收益
            List<StatisticUserBillAmountReponseDTO> list =  receivedStatisticFuture.get();
            if(CollectionUtils.isEmpty(list)) {
            	responseVO.setTotalIncome(BigDecimal.ZERO);
            }else {
            	responseVO.setTotalIncome(list.get(0).getAmount());
            }
            LoanIndexQueryResponseDTO indexQueryResponseDTO = loanIndexQueryFuture.get();
            if(Objects.nonNull(indexQueryResponseDTO)&&Objects.nonNull(indexQueryResponseDTO.getToRepayCurrentMonth())&&BigDecimal.ZERO.compareTo(indexQueryResponseDTO.getToRepayCurrentMonth())<0) {
            	responseVO.setToRepayCurrentMonthMsg("本月应还"+df.format(indexQueryResponseDTO.getToRepayCurrentMonth())+"元");
            }
        } catch (InterruptedException e) {
            log.error("远程调用服务失败InterruptedException:", e);
        } catch (ExecutionException e) {
            log.error("远程调用服务失败ExecutionException:", e);

        }

        // 债权转让new图标标识: 0不显示，1显示
        try {
            DateTime date = new DateTime(FastDateFormat.getInstance("yyyy-MM-dd").parse(onlineTime)).plusMonths(1);
            if(date.toDate().before(new Date())){
                responseVO.setCreditorRights(Byte.valueOf("0"));
            } else {
                String userIsNewLogoClickKey = TradeRedisKey.MYSELF_CREDITOR_IS_SHOW + userId;
                if(redisTemplate.hasKey(userIsNewLogoClickKey)){
                    responseVO.setCreditorRights(Byte.valueOf("0"));
                }else {
                    responseVO.setCreditorRights(Byte.valueOf("1"));
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

        responseVO.setInvitingGuideLanguage(this.invitingGuideLanguage(userId));
        responseVO.setCouponGuideLanguage(this.couponGuideLanguage(userId));
        return Result.with(responseVO);
    }

     // 邀请文案
     private String invitingGuideLanguage(String userId){
        String invitingGuideLanguage = "";
         InviteInviteeSummaryRespDTO inviteeSummary = inviterDetailDubboService.getInviteeSummary(userId);
         log.info("invitingGuideLanguage. inviteeSummary={}", JSON.toJSONString(inviteeSummary));

         if(inviteeSummary == null || inviteeSummary.getInviteUserCount() <= 0){
             List<TradeConfigEnum> enumList = new ArrayList<>();
             enumList.add(TradeConfigEnum.SLOGAN_NO_INVITATION_RECORDING);      // 引导语.无邀请记录时
             Map<String, String> tradeConfig = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);

             if (!CollectionUtils.isEmpty(tradeConfig) && StringUtils.isNotBlank(tradeConfig.get(TradeConfigEnum.SLOGAN_NO_INVITATION_RECORDING.getConfigKey()))) {
                 invitingGuideLanguage = tradeConfig.get(TradeConfigEnum.SLOGAN_NO_INVITATION_RECORDING.getConfigKey());
             }
         }else {
             InviteMoneySummaryRespDTO moneySummary = inviterDetailDubboService.getMoneySummary(userId);
             log.info("invitingGuideLanguage. moneySummary={}", JSON.toJSONString(moneySummary));

             if(moneySummary != null && moneySummary.getMoneyAmount() != null){
                 BigDecimal money = new BigDecimal(moneySummary.getMoneyAmount()).setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
                 invitingGuideLanguage = "累计获得奖励"+ money + "元";
             }
         }
         return invitingGuideLanguage;
     }

    /**
     * 1、账户有红包和加息券，在有效期不足3天（含3天）时，提示：红包、加息券即将过期；仅有红包或加息券一种即将过期的提示：红包（加息券）即将过期。
     * 2、账户有红包和加息券且有效期大于3天，提示：您有待使用红包、加息券；仅有红包或加息券一种的提示：您有待使用红包（加息券）
     */
    private String couponGuideLanguage(String userId){
        String couponGuideLanguage = null;
        SummarizeListRequestDTO requestDTO = new SummarizeListRequestDTO();
        requestDTO.setUserId(userId);
        SummarizeListResponseDTO summaryRespDTO = giftDubboService.summarizeList(requestDTO);
        log.info("invitingGuideLanguage. summaryRespDTO={}", JSON.toJSONString(summaryRespDTO));

        if(summaryRespDTO != null){
            Integer hongBaoCount = Integer.valueOf("0");
            Integer jiaXiJuanCount = Integer.valueOf("0");
            Integer hongBaoExpire = Integer.valueOf("0");
            Integer jiaXiJuanExpire = Integer.valueOf("0");
            List<GiftSummarizeDTO> giftSummarizeDTOList = summaryRespDTO.getGiftSummarizeDTOList();
            for(GiftSummarizeDTO giftSummarizeDTO : giftSummarizeDTOList){
                // 提现红包、投资返现红包、借款返现红包、投资加息券  (是否即将过期 0：否；1：是)
                if(GoodsTypeDicEnum.TIXIAN_HB.getId().equals(giftSummarizeDTO.getGoodsType())
                        || GoodsTypeDicEnum.TOUZI_FXQ.getId().equals(giftSummarizeDTO.getGoodsType())
                        || GoodsTypeDicEnum.JIEKUAN_FXQ.getId().equals(giftSummarizeDTO.getGoodsType())
                        || GoodsTypeDicEnum.JIEKUAN_LILV_ZKK.getId().equals(giftSummarizeDTO.getGoodsType())){
                    hongBaoCount = giftSummarizeDTO.getTotalNumber() > 0 ? hongBaoCount + 1 : hongBaoCount;
                    hongBaoExpire = giftSummarizeDTO.getIsWillSoonExpire().equals(Byte.valueOf("1")) ? hongBaoExpire + 1 : hongBaoExpire;
                }
                if(GoodsTypeDicEnum.TOUZI_JXQ.getId().equals(giftSummarizeDTO.getGoodsType())){
                    jiaXiJuanCount = giftSummarizeDTO.getTotalNumber() > 0 ? jiaXiJuanCount + 1 : jiaXiJuanCount;
                    jiaXiJuanExpire = giftSummarizeDTO.getIsWillSoonExpire().equals(Byte.valueOf("1")) ? jiaXiJuanExpire + 1 : jiaXiJuanExpire;
                }
            }
            if(hongBaoCount > 0 && jiaXiJuanCount > 0 && hongBaoExpire == 0 && jiaXiJuanExpire == 0){
                couponGuideLanguage = "您有待使用红包、加息券";
            }else if(hongBaoCount > 0 && jiaXiJuanCount > 0 && hongBaoExpire > 0 && jiaXiJuanExpire > 0){
                couponGuideLanguage = "红包、加息券即将过期";
            }else if(hongBaoCount > 0 && jiaXiJuanCount == 0 && hongBaoExpire == 0){
                couponGuideLanguage = "您有待使用红包";
            }else if(jiaXiJuanCount > 0 && hongBaoCount == 0 && jiaXiJuanExpire == 0){
                couponGuideLanguage = "您有待使用加息券";
            }else if((hongBaoCount > 0 && jiaXiJuanCount > 0 && hongBaoExpire > 0 && jiaXiJuanExpire == 0)
                    || (hongBaoCount > 0 && jiaXiJuanCount == 0 && hongBaoExpire > 0 )){
                couponGuideLanguage = "红包即将过期";
            }else if((hongBaoCount > 0 && jiaXiJuanCount > 0 && hongBaoExpire == 0 && jiaXiJuanExpire > 0)
                    || (jiaXiJuanCount > 0 && hongBaoCount == 0 && jiaXiJuanExpire > 0 )){
                couponGuideLanguage = "加息券即将过期";
            }
        }
        return couponGuideLanguage;
    }

    @PostMapping("/myselfCreditorNewLogoIsClick")
    @ApiOperation("(5.3.0)记录用户是否已经点击债权转让new图标标识-黄敏")
    public Result<Empty> myselfCreditorNewLogoIsClick() {
        String userId = PrincipalContext.getUserId();
        log.info("UserBasicController.myselfCreditorNewLogoIsClick userId={}",userId);

        if(StringUtil.isBlank(userId)){
            throw new BizException("USR10019");
        }

        String userIsNewLogoClickKey = TradeRedisKey.MYSELF_CREDITOR_IS_SHOW + userId;
        redisTemplate.opsForValue().set(userIsNewLogoClickKey, String.valueOf("0"), 30, TimeUnit.DAYS); // 0 未显示 1已显示

        return Result.with(Empty.getInstance());
    }

    @PostMapping("/myAccountIndex")
    @ApiOperation("H5--我的账户(李健)")
    public Result<MyAccountResponseVO> myAccountIndex() {
        String userId = getUserIdFromAuth();
        MyAccountResponseVO responseVO = new MyAccountResponseVO();
        Future<MyPageUserInfoDTO> myPageUserfuture = RpcContext.getContext().asyncCall(() -> userBasicInfoDubboService.getMyPageUserInfo(userId));
        QueryMoneyTotalRequestDTO queryMoneyTotalRequest = new QueryMoneyTotalRequestDTO();
        queryMoneyTotalRequest.setUserId(userId);
        Future<QueryMoneyTotalResponseDTO> investmenTotalResponse = RpcContext.getContext().asyncCall(() -> moneyTotalDubboService.queryMoneyTotal(queryMoneyTotalRequest));

        InvestAmountStatisticsRequestDTO investAmountStatisticsRequestDTO = new InvestAmountStatisticsRequestDTO();
        investAmountStatisticsRequestDTO.setUserId(userId);
        investAmountStatisticsRequestDTO.setQueryType(Byte.valueOf("0"));
        Future<InvestAmountStatisticsResponseDTO> dueInFuture = RpcContext.getContext().asyncCall(() -> investOrderDubboService.myInvestAmountStatistics(investAmountStatisticsRequestDTO));

        StatisticUserBillAmountRequestDTO statisticUserBillAmountRequestDTO = new StatisticUserBillAmountRequestDTO();
        List<BillAmountStatisticsEnum> billAmountStatisticsEnums = Arrays.asList(BillAmountStatisticsEnum.ACCUMULATED_PROFIT);
        statisticUserBillAmountRequestDTO.setUserId(userId);
        statisticUserBillAmountRequestDTO.setBillAmountStatisticsEnums(billAmountStatisticsEnums);

        Future<List<StatisticUserBillAmountReponseDTO>> receivedStatisticFuture = RpcContext.getContext().asyncCall(() -> userBillStatisticsDubboService.statisticUserBillAmounts(statisticUserBillAmountRequestDTO));
        try {
            //取用户基本信息
            MyPageUserInfoDTO myPageUserInfo = myPageUserfuture.get();
            responseVO.setNickName(myPageUserInfo.getNickName());
            responseVO.setHeadImage(myPageUserInfo.getHeadImage());
            responseVO.setEvaluationLevel(myPageUserInfo.getEvaluationLevel());
            //取投资统计信息
            QueryMoneyTotalResponseDTO investmenTotal = investmenTotalResponse.get();
            responseVO.setBalanceAmount(investmenTotal.getInvestorAvailableBalance());
            responseVO.setCollectAmount(investmenTotal.getDueInCorpus());

            InvestAmountStatisticsResponseDTO dueIn = dueInFuture.get();
            responseVO.setCollectInterest(dueIn.getReferenceInterest());

            responseVO.setCumulativeInterest(BigDecimal.ZERO);

            List<StatisticUserBillAmountReponseDTO> receivedStatistic = receivedStatisticFuture.get();
            log.info("myAccountIndex userId={}, receivedStatistic:{}", userId, JSON.toJSON(receivedStatistic));

            for (StatisticUserBillAmountReponseDTO statisticUserBillAmountReponseDTO: receivedStatistic) {
                if(statisticUserBillAmountReponseDTO != null) {
                    if(BillAmountStatisticsEnum.ACCUMULATED_PROFIT.equals(statisticUserBillAmountReponseDTO.getBillAmountStatisticsEnum())){
                        responseVO.setCumulativeInterest(statisticUserBillAmountReponseDTO.getAmount() == null ? BigDecimal.ZERO : statisticUserBillAmountReponseDTO.getAmount());
                    }
                }
            }
        } catch (Exception e) {
            log.error("远程调用服务失败InterruptedException:", e);
        }
        return Result.with(responseVO);
    }

    @ApiOperation("密码管理信息 (张万里)")
    @PostMapping("/passwordManagement")
    public Result<PasswordManagementResponseVO> queryPasswordManagementInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        PasswordManagementResponseVO responseVO = new PasswordManagementResponseVO();
        List<AccountBaseResponse> accounts = accountDubboService.listNiiwooAccountByUserId(userId);
        
        //若未开通存管户，交易密码通栏文案显示为“未设置”，点击后弹窗引导用户开通存管户；
        //若未激活存管户，交易密码通栏文案显示为“未设置”，点击后弹窗引导用户激活存管户；
        // 若用户已开户或已激活存管户，通栏文案显示文案为“已设置”，点击后根据交易密码修改流程展示页面；
        if (accounts == null || accounts.isEmpty()) {
            responseVO.setAccountStatus(0);
            responseVO.setNonePwdInvestStatus(0);
        } else {
            boolean active = accounts.stream().anyMatch(account -> account.getImportUserActiva().intValue() == 1);
            if (active) {
                responseVO.setAccountStatus(2);
            } else {
                responseVO.setAccountStatus(1);
            }
            boolean tender = accounts.stream().anyMatch(account -> account.getAccountRole().equals(UserRoleEnum.INVESTOR.getValue()) && account.getTender().intValue() == 1);
            responseVO.setNonePwdInvestStatus(tender ? 1 : 0);
            
            boolean repayment = accounts.stream().anyMatch(account -> account.getAccountRole().equals(UserRoleEnum.BORROWERS.getValue()) && account.getRepayment().intValue() == 1);
            responseVO.setAutoRepaymentStatus(repayment ? 1 : 0);
        }
        UserSecurityPasswordResponseDTO responseDTO = userLoginAccountService.queryUserSecurityPassword(userId);
        responseVO.setLoginPwdSettingStatus(responseDTO.getLoginPassword());
        
        // 未结清的借款数量
        Integer notSettlementLoanCount = myLoanDubboService.queryNotSettlementLoanCount(userId);
        responseVO.setExistNotSettlementLoan((notSettlementLoanCount != null && notSettlementLoanCount > 0) ? 1 : 0);

        // 代扣还款开通状态
        AccountBaseResponse borrowAccount = accountDubboService.getNiiwooAccount(userId, UserRoleEnum.BORROWERS);
        if (borrowAccount != null && borrowAccount.getAccountId() != null) { // 有借款账户
            WithholdProtocolResultDTO withholdProtocolResultDTO = withholdProtocolDubboService.getWithholdProtocolResultForLocal(userId, OrgConstant.NIIWOO_ORG_ID);
            log.info("queryPasswordManagementInfo userId:{}, withholdProtocolResultDTO: {}", userId, JSON.toJSONString(withholdProtocolResultDTO));

            if (Boolean.TRUE.equals(withholdProtocolResultDTO.getResult())) {
                if (withholdProtocolResultDTO.getExpire() == 1) {
                    responseVO.setWithholdOpenStatus(1); // 已开通代扣
                } else if (withholdProtocolResultDTO.getExpire() == 0) {
                    responseVO.setWithholdOpenStatus(2); // 已失效
                }
            } else {
                responseVO.setWithholdOpenStatus(0); // 未开通代扣
            }
        } else { // 没有借款账户
            responseVO.setWithholdOpenStatus(-1); // 隐藏入口
        }

        return Result.with(responseVO);
    }

    @ApiOperation("自动还款信息 (吴科)")
    @PostMapping("/queryAutoRepaymentInfo")
    public Result<AutoRepaymentInfoResponseVO> queryAutoRepaymentInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        AutoRepaymentInfoResponseVO responseVO = new AutoRepaymentInfoResponseVO();
        List<AccountBaseResponse> accounts = accountDubboService.listNiiwooAccountByUserId(userId);

        if (accounts == null || accounts.isEmpty()) {
            responseVO.setAccountStatus(0);
        } else {
            boolean active = accounts.stream().anyMatch(account -> account.getImportUserActiva().intValue() == 1);
            if (active) {
                responseVO.setAccountStatus(2);
            } else {
                responseVO.setAccountStatus(1);
            }

            boolean repayment = accounts.stream().anyMatch(account -> account.getAccountRole().equals(UserRoleEnum.BORROWERS.getValue()) && account.getRepayment().intValue() == 1);
            responseVO.setAutoRepaymentStatus(repayment ? 1 : 0);
        }

        return Result.with(responseVO);
    }

    @ApiOperation(value = "开启免密投资 (张万里)")
    @PostMapping(path = "/enableNonePwdInvest")
    public Result<LanMaoGatewayDTO> enableInvestWithoutPassword(@RequestBody(required = false) @Valid AuthorizeNonePwdInvestRequestVO request) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        UserAccountPropertyResponse userAccountPropertyResponse = userAccountDubboService.getAccountProperty(userId);
        AccountBaseResponse accountInfo = null ;
        if( userAccountPropertyResponse.getUserType().equals(UserTypeEnum.PERSONAL)) {
            accountInfo = accountDubboService.loadNiiwooAccount(userId, UserRoleEnum.INVESTOR);
        }else{
            accountInfo = accountDubboService.loadOrgAccount(userId, userId);
        }
        UserAuthorizationRequest authorizationRequest = new UserAuthorizationRequest();
        authorizationRequest.setPlatformUserNo(accountInfo.getAccountNo());
        authorizationRequest.setRequestNo(lanMaoSequence.getRequestNo());
        authorizationRequest.setAuthList(UserAuthorizationEnum.TENDER.name());
        authorizationRequest.setFailTime(new DateTime().plusYears(99).toDate());
        authorizationRequest.setAmount("1000000.00");
        if (request != null) {
            authorizationRequest.setNiiwooRedirectUrl(request.getRedirectUrl());
        }
        LanMaoGatewayDTO gatewayDTO = lanMaoGatewayService.userAuthorization(authorizationRequest);
        return Result.with(gatewayDTO);
    }
    
    @ApiOperation(value = "关闭免密投资 (张万里)")
    @PostMapping(path = "/disableNonePwdInvest")
    public Empty disableInvestWithoutPassword() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        //AccountBaseResponse account = accountDubboService.loadNiiwooAccount(userId, UserRoleEnum.INVESTOR);
        UserAccountPropertyResponse userAccountPropertyResponse = userAccountDubboService.getAccountProperty(userId);
        AccountBaseResponse account = null ;
        if( userAccountPropertyResponse.getUserType().equals(UserTypeEnum.PERSONAL)) {
            account = accountDubboService.loadNiiwooAccount(userId, UserRoleEnum.INVESTOR);
        }else{
            account = accountDubboService.loadOrgAccount(userId, userId);
        }
        accountDubboService.disableUserAuthorization(account.getAccountNo(), Sets.newHashSet(UserAuthorizationEnum.TENDER));
        //关闭免密投资后需要关闭用户的自动投资
        autoInvestDubboService.disableAutoInvest(userId);
        return Empty.getInstance();
    }
    
    @ApiOperation(value = "开启自动还款 (廖君君)")
    @PostMapping(path = "/enableAutoRepayment")
    public Result<LanMaoGatewayDTO> enableAutoRepayment(@RequestBody(required = false) @Valid AuthorizeNonePwdInvestRequestVO request) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        AccountBaseResponse accountInfo = accountDubboService.loadNiiwooAccount(userId, UserRoleEnum.BORROWERS);
        UserAuthorizationRequest authorizationRequest = new UserAuthorizationRequest();
        authorizationRequest.setPlatformUserNo(accountInfo.getAccountNo());
        authorizationRequest.setRequestNo(lanMaoSequence.getRequestNo());
        authorizationRequest.setAuthList(UserAuthorizationEnum.REPAYMENT.name());
        authorizationRequest.setFailTime(new DateTime().plusYears(99).toDate());
        authorizationRequest.setAmount("1000000.00");
        if (request != null) {
            authorizationRequest.setNiiwooRedirectUrl(request.getRedirectUrl());
        }
        LanMaoGatewayDTO gatewayDTO = lanMaoGatewayService.userAuthorization(authorizationRequest);
        return Result.with(gatewayDTO);
    }
    
    @ApiOperation(value = "关闭自动还款(廖君君)")
    @PostMapping(path = "/disableAutoRepayment")
    public Empty disableAutoRepayment() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        
        Integer notSettlementLoanCount = myLoanDubboService.queryNotSettlementLoanCount(userId);
        if (notSettlementLoanCount != null && notSettlementLoanCount > 0){
        	throw new BizException("ACC11002");// 存在未结清标的
        }

        AccountBaseResponse accountBaseResponse = accountDubboService.loadNiiwooAccount(userId, UserRoleEnum.BORROWERS);
        accountDubboService.disableUserAuthorization(accountBaseResponse.getAccountNo(), Sets.newHashSet(UserAuthorizationEnum.REPAYMENT));
        return Empty.getInstance();
    }

    @ApiOperation(value = "存管账户信息")
    @PostMapping(path = "/bankAccount")
    public Result<BankAccountInfoVO> getAccountInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("存管账户信息###userId={}", userId);
        DataStatusResponseDTO statusResponseDTO = userStatusDubboService.getByUserIdAndType(userId, UserDataTypeEnum.BIND_BANK_CARD);
        if (statusResponseDTO == null) {
            log.info("存管账户信息###查询绑卡卡状态为空, userId={}", userId);
            throw new BizException(LoginAccountErrorCode.NOT_OPEN_ACCOUNT_YET);
        }
        log.info("存管账户信息###查询绑卡卡状态, data={}", JSON.toJSONString(statusResponseDTO));
        UserDataStatusEnum.OpenBankAccountStatus status = UserDataStatusEnum.OpenBankAccountStatus.of(statusResponseDTO.getDataStatus());
        if (status == null) {
            log.info("存管账户信息###转换绑卡卡状态为空, userId={}", userId);
            throw new BizException(LoginAccountErrorCode.NOT_OPEN_ACCOUNT_YET);
        }
        log.info("存管账户信息###转换绑卡卡状态, status={}", status);
        switch (status) {
            case NOT_BIND:
                throw new BizException(LoginAccountErrorCode.NOT_OPEN_ACCOUNT_YET);
            case NOT_ACTIVE:
                throw new BizException(LoginAccountErrorCode.NOT_ACTIVATE_ACCOUNT_YET);
        }
        BankAccountInfoVO vo = new BankAccountInfoVO();
        Optional.ofNullable(bankCardDubboService.getUserBankCardInfo(userId)).ifPresent(d -> {
            log.info("存管账户信息###查询银行卡信息, data={}", JSON.toJSONString(d));
            vo.setName(d.getRealName());
            vo.setIdCardNo(privacyMasks.maskIdCard(d.getIdCard()));
            vo.setBankCardNo(privacyMasks.maskBankCard(d.getBankAccountNo()));
            vo.setBankCardMobileNo(privacyMasks.maskMobile(d.getMobileNo()));
        });
        log.info("存管账户信息###返回结果, data={}", JSON.toJSONString(vo));
        return Result.with(vo);
    }

    @ApiOperation(value = "存管账户信息h5")
    @PostMapping(path = "/bankAccount/h5")
    @AuthIgnore
    public Result<BankAccountInfoVO> getAccountInfoH5(@RequestBody @Valid BankAccountInfoRequestVO requestVO) {
        String userId;
        if (requestVO.getChannel() == null) {
            userId = r360RedisService.verifyTokenAndGetUserId(requestVO.getToken());
        } else {
            userId = r360RedisService.verifyTokenAndGetUserId(requestVO.getToken(), requestVO.getChannel());
        }
        accountDubboService.loadActivedNiiwooAccount(userId, UserRoleEnum.BORROWERS);
        BankAccountInfoVO vo = new BankAccountInfoVO();
        Optional.ofNullable(bankCardDubboService.getUserBankCardInfo(userId))
                .ifPresent(d -> {
                    vo.setName(d.getRealName());
                    vo.setIdCardNo(d.getIdCard());
                    vo.setBankCardNo(d.getBankAccountNo());
                    vo.setBankCardMobileNo(d.getMobileNo());
                    vo.setBankCode(d.getBankCode());
                });
        return Result.with(vo);
    }


    @ApiOperation(value = "校验是否需要登录验证码")
    @RequestMapping(path = "/login/smsCodeStatus", method = RequestMethod.POST)
    @AuthIgnore
    public Empty getLoginSMSStatus(@RequestBody @Valid LoginSMSStatusRequestVO requestVO) {
        LoginAccountRequestDTO dto = new LoginAccountRequestDTO();
        dto.setLoginMobileNo(requestVO.getLoginMobileNo());
        userLoginAccountService.getLoginSMSStatus(dto);
        return Empty.getInstance();
    }

    @PostMapping("/tradePwdReset")
    @ApiOperation("修改交易密码")
    public Result<TradePwdResetPrepareResponseVO> resetTradePwd(@RequestBody @Valid TradePwdResetPrepareRequestVO resetPrepareVO) {
        return resetBankInfo(accountBaseResponse -> {
            ChangeTradePasswordRequest request = new ChangeTradePasswordRequest();
            request.setRequestNo(lanMaoSequence.getRequestNo());
            request.setPlatformUserNo(accountBaseResponse.getAccountNo());
            request.setTimestamp(new Date());
            request.setNiiwooRedirectUrl(resetPrepareVO.getRedirectUrl());
            return lanMaoGatewayService.changeTradePassword(request);
        });

    }

    @PostMapping("/tradePwdReset/h5")
    @ApiOperation("修改交易密码")
    @AuthIgnore
    public Result<TradePwdResetPrepareResponseVO> resetTradePwdH5(@RequestBody @Valid TradePwdResetPrepareH5RequestVO requestVO) {
        String userId = validThirdToken(requestVO.getToken(), requestVO.getChannel());
        String orgId = getOrgId(requestVO.getChannel(), requestVO.getOrgCode());
        return resetBankInfo(accountBaseResponse -> {
            ChangeTradePasswordRequest request = new ChangeTradePasswordRequest();
            request.setRequestNo(lanMaoSequence.getRequestNo());
            request.setPlatformUserNo(accountBaseResponse.getAccountNo());
            request.setTimestamp(new Date());
            request.setNiiwooRedirectUrl(requestVO.getRedirectUrl());
            return lanMaoGatewayService.changeTradePassword(request);
        }, userId, orgId);
    }

    @PostMapping("/bankMobileNoReset")
    @ApiOperation("修改银行卡预留手机号码")
    public Result<TradePwdResetPrepareResponseVO> resetBankMobileNo(@RequestBody @Valid TradePwdResetPrepareRequestVO resetPrepareVO) {
        return resetBankInfo(accountBaseResponse -> {
            ChangeBankCardMobileNoRequest request = new ChangeBankCardMobileNoRequest();
            request.setRequestNo(lanMaoSequence.getRequestNo());
            request.setPlatformUserNo(accountBaseResponse.getAccountNo());
            request.setTimestamp(new Date());
            request.setNiiwooRedirectUrl(resetPrepareVO.getRedirectUrl());
            return lanMaoGatewayService.changeBankCardMobileNo(request);
        });

    }

    @PostMapping("/bankMobileNoReset/h5")
    @ApiOperation("修改银行卡预留手机号码")
    @AuthIgnore
    public Result<TradePwdResetPrepareResponseVO> resetBankMobileNoH5(@RequestBody @Valid TradePwdResetPrepareH5RequestVO requestVO) {
        String userId = validThirdToken(requestVO.getToken(), requestVO.getChannel());
        String orgId = getOrgId(requestVO.getChannel(), requestVO.getOrgCode());
        return resetBankInfo(accountBaseResponse -> {
            ChangeBankCardMobileNoRequest request = new ChangeBankCardMobileNoRequest();
            request.setRequestNo(lanMaoSequence.getRequestNo());
            request.setPlatformUserNo(accountBaseResponse.getAccountNo());
            request.setTimestamp(new Date());
            request.setNiiwooRedirectUrl(requestVO.getRedirectUrl());
            return lanMaoGatewayService.changeBankCardMobileNo(request);
        }, userId, orgId);
    }

    private Result<TradePwdResetPrepareResponseVO> resetBankInfo(Function<AccountBaseResponse, LanMaoGatewayDTO> f) {
        return Optional.ofNullable(accountDubboService.listNiiwooAccountByUserId(String.valueOf(PrincipalContext.getUserId())))
                .map(list -> {
                    AccountBaseResponse accountBaseResponse = list.stream()
                            .filter(a -> {
                                UserRoleEnum role = UserRoleEnum.enumOf(a.getAccountRole());
                                return (role == UserRoleEnum.BORROWERS || role == UserRoleEnum.INVESTOR) && a.getImportUserActiva().equals(AccountActiveEnum.ACTIVATED.getValue());
                            })
                            .findFirst()
                            .orElseThrow(() -> new BizException(AccountRegisterErrorCode.ACCOUNT_NOT_EXISTS));
                    LanMaoGatewayDTO gatewayDTO = f.apply(accountBaseResponse);
                    TradePwdResetPrepareResponseVO responseVO = new TradePwdResetPrepareResponseVO();
                    responseVO.setAction(gatewayDTO.getAction());
                    responseVO.setParams(gatewayDTO.getParams());
                    return Result.with(responseVO);
                }).orElseThrow(() -> new BizException(AccountRegisterErrorCode.ACCOUNT_NOT_EXISTS));

    }

    private Result<TradePwdResetPrepareResponseVO> resetBankInfo(Function<AccountBaseResponse, LanMaoGatewayDTO> f, String userId, String orgId) {
        return Optional.ofNullable(accountDubboService.listNiiwooAccountByUserId(userId, orgId))
                .map(list -> {
                    AccountBaseResponse accountBaseResponse = list.stream()
                            .filter(a -> {
                                UserRoleEnum role = UserRoleEnum.enumOf(a.getAccountRole());
                                return (role == UserRoleEnum.BORROWERS || role == UserRoleEnum.INVESTOR) && a.getImportUserActiva().equals(AccountActiveEnum.ACTIVATED.getValue());
                            })
                            .findFirst()
                            .orElseThrow(() -> new BizException(AccountRegisterErrorCode.ACCOUNT_NOT_EXISTS));
                    LanMaoGatewayDTO gatewayDTO = f.apply(accountBaseResponse);
                    TradePwdResetPrepareResponseVO responseVO = new TradePwdResetPrepareResponseVO();
                    responseVO.setAction(gatewayDTO.getAction());
                    responseVO.setParams(gatewayDTO.getParams());
                    return Result.with(responseVO);
                }).orElseThrow(() -> new BizException(AccountRegisterErrorCode.ACCOUNT_NOT_EXISTS));
    }

    @ApiOperation(value = "获取用户基本资料(吴科)")
    @PostMapping("/getUserBasicData")
    public Result<UserBasicDataResponseVO> getUserBasicData(@RequestBody @Valid UserBasicDataRequestVO requestVO) {
        String userId = requestVO.getUserId();
        log.info("getUserBasicData.userId={} start", userId);
        UserBasicInfoResponseDTO userBasicInfoResponseDTO = userBasicInfoDubboService.selectUserBaseInfo(userId);
        log.info("getUserBasicData.userId={},userBasicInfoResponseDTO={}", userId, JSON.toJSONString(userBasicInfoResponseDTO));

        UserBasicDataResponseVO userBasicDataResponseVO = new UserBasicDataResponseVO();
        if(userBasicInfoResponseDTO != null){
            userBasicDataResponseVO.setUserId(userBasicInfoResponseDTO.getUserId());
            userBasicDataResponseVO.setNickName(userBasicInfoResponseDTO.getNickName());
            userBasicDataResponseVO.setNiiwooCode(userBasicInfoResponseDTO.getNiiwooCode());
            userBasicDataResponseVO.setNiiwooScore(userBasicInfoResponseDTO.getNiiwooScore());
            userBasicDataResponseVO.setHeadImage(userBasicInfoResponseDTO.getHeadImage());
        }
        DataStatusResponseDTO nameAuthStatusDTO = userStatusDubboService.getByUserIdAndType(userId, UserDataTypeEnum.TWO_ELEMENT);
        log.info("getUserBasicData.userId={},nameAuthStatusDTO={}", userId, JSON.toJSONString(nameAuthStatusDTO));

        Byte nameAuthStatus = (nameAuthStatusDTO == null ? UserDataStatusEnum.RealNameAuthStatus.NOT_CERTIFIED.getStatus() : nameAuthStatusDTO.getDataStatus());
        userBasicDataResponseVO.setNameAuthStatus(nameAuthStatus);
        int loanTimes = speedLoanDubboService.getUserLoanSuccessTimes(userId);
        log.info("getUserBasicData.userId={},loanTimes={}", userId, loanTimes);

        int repeatLoanTimes = loanTimes>1?(loanTimes-1):0; //复借笔数
        userBasicDataResponseVO.setLoanTimes(repeatLoanTimes);
        log.info("getUserBasicData.userId={},userBasicDataResponseVO={}", userId, JSON.toJSONString(userBasicDataResponseVO));

        return Result.with(userBasicDataResponseVO);
    }

    @ApiOperation(value = "保存极光推送ID")
    @PostMapping("/jiGuangPushId")
    public Empty saveJiGuangPushId(@RequestBody @Valid SaveJiGuangPushIdRequestVO requestVO) {
        userLoginAccountDubboService.saveJiGuangPushId(String.valueOf(PrincipalContext.getUserId()), requestVO.getJiGuangPushId());
        return Empty.getInstance();
    }

    @ApiOperation(value = "对外引流")
    @PostMapping("/recommend/outSide")
    public Empty recommendOutSide() {
        return Empty.getInstance();
    }




    @ApiOperation(value = "(5.1.5)检查用户是否可以更换手机号")
    @PostMapping("/isChangeMobileNo")
    public Result<IsChangeMobileNoResponseVO> isChangeMobileNo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserBasicController.smsChangeMobileNo userId={}", userId);

        // 查询用户是否有逾期尚未结清的标的
        IsChangeMobileNoResponseVO responseVO = new IsChangeMobileNoResponseVO();
        responseVO.setBankAccountNo("");
        List<Integer> subStatus = new ArrayList<>();
        subStatus.add(ProjectSubStatusEnum.REPAYING_OVERDUE.getSubStatus());
        subStatus.add(ProjectSubStatusEnum.REPAYING_BAD.getSubStatus());

        if(projectDubboService.selectProjectCountBySubStatus(userId,subStatus) > 0){
            responseVO.setResult(MobileChangeRecordEnum.ChangeResultEnum.OVERDUE_LOAN.getValue());
            responseVO.setPromptMessage(ChangeMobilePromptMessage.OVERDUE_LOAN_TEMPLATE);
            return Result.with(responseVO);
        }

        if(projectDubboService.queryProjectByStatus(userId, Arrays.asList(ProjectStatusEnum.CHECKING, ProjectStatusEnum.COLLECTING)) > 0){
            responseVO.setResult(MobileChangeRecordEnum.ChangeResultEnum.CHECKING.getValue());
            responseVO.setPromptMessage(ChangeMobilePromptMessage.CHECKING_TEMPLATE);
            return Result.with(responseVO);
        }

        // 查询手机修改期限
        if(mobileChangeRecordDubboService.selectMobileChangeRecord(userId)){
            responseVO.setResult(MobileChangeRecordEnum.ChangeResultEnum.LIMIT_3_MONTHS.getValue());
            responseVO.setPromptMessage(ChangeMobilePromptMessage.LIMIT_3_MONTHS_TEMPLATE);
            return Result.with(responseVO);
        }

        // 查询用户实名信息
        Byte realNameStatus = mobileChangeRecordDubboService.selectUserDataStatus(userId);
        if(MobileChangeRecordEnum.ChangePhoneNumberEnum.OPEN_AN_ACCOUNT.getValue().equals(realNameStatus)){
            BankCardDTO bankCardDTO = bankCardDubboService.getUserBankCardInfo(userId);
            responseVO.setBankAccountNo(bankCardDTO != null ?
                   bankCardDTO.getBankAccountNo().substring(bankCardDTO.getBankAccountNo().length()-3, bankCardDTO.getBankAccountNo().length()) : "");
        }
        responseVO.setRealNameStatus(realNameStatus);
        responseVO.setPromptMessage(ChangeMobilePromptMessage.PROMPT_MESSAGE);
        responseVO.setResult(MobileChangeRecordEnum.ChangeResultEnum.CAN_CHANGE.getValue());
        return Result.with(responseVO);
    }

    @ApiOperation(value = "(5.1.5)更换手机短信验证")
    @PostMapping("/smsChangeMobileNo")
    public Empty smsChangeMobileNo(@RequestBody @Valid SMSChangeMobileNoRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserBasicController.smsChangeMobileNo userId={}", userId);

        if (StringUtils.isBlank(requestVO.getMobileNo()) || !ParameterValidator.isMobileNo(requestVO.getMobileNo())) {
            throw new BizException(LoginAccountErrorCode.LOGIN_MOBILENO_FORMAT_ERROR);
        }

        SMSChangeMobileNoRequestDTO requestDTO = new SMSChangeMobileNoRequestDTO();
        requestDTO.setUserId(userId);
        requestDTO.setSmsCode(requestVO.getSmsCode());
        requestDTO.setMobileNo(privacyMasks.encryptPrivacy(requestVO.getMobileNo()));
        mobileChangeRecordDubboService.smsChangeMobileNo(requestDTO);

        return Empty.getInstance();
    }

    @ApiOperation(value = "(5.1.5)更换手机实名验证")
    @PostMapping("/realNameChangePhoneNumber")
    public Empty realNameChangeMobileNo(@RequestBody @Valid RealNameChangeMobileNoRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserBasicController.realNameChangeMobileNo userId={}", userId);

        if(!MobileChangeRecordEnum.ChangePhoneNumberEnum.PASS_CERTIFIED_NO_ACCOUNT_OPENING.getValue().equals(requestVO.getType())
                && !MobileChangeRecordEnum.ChangePhoneNumberEnum.OPEN_AN_ACCOUNT.getValue().equals(requestVO.getType())){
            throw new BizException("USR10035");
        }

        UserIdentityInfoResponseDTO userIdentityInfoResponseDTO = userIdentityDubboService.get(userId);
        if(MobileChangeRecordEnum.ChangePhoneNumberEnum.PASS_CERTIFIED_NO_ACCOUNT_OPENING.getValue().equals(requestVO.getType())){
            log.info("UserBasicController.realNameChangeMobileNo userIdentityInfoResponseDTO={}", JSON.toJSONString(userIdentityInfoResponseDTO));
            if(userIdentityInfoResponseDTO == null){
                throw new BizException("USR10034");
            }
            if(!requestVO.getRealName().equals(userIdentityInfoResponseDTO.getName())
                    || !requestVO.getIdCard().equals(userIdentityInfoResponseDTO.getIdCard())){
                throw new BizException("USR10034");
            }
        }

        if(MobileChangeRecordEnum.ChangePhoneNumberEnum.OPEN_AN_ACCOUNT.getValue().equals(requestVO.getType())){
            BankCardDTO bankCardDTO = bankCardDubboService.getUserBankCardInfo(userId);
            log.info("UserBasicController.realNameChangeMobileNo bankCardDTO={}", JSON.toJSONString(bankCardDTO));
            if(bankCardDTO == null){
                throw new BizException("USR10034");
            }
            if(!requestVO.getRealName().equals(userIdentityInfoResponseDTO.getName())
                    || !requestVO.getIdCard().equals(userIdentityInfoResponseDTO.getIdCard())
                    || !requestVO.getBankAccountNo().equals(bankCardDTO.getBankAccountNo())){
                throw new BizException("USR10034");
            }

        }
        return Empty.getInstance();
    }

    @ApiOperation(value = "(5.1.5)新手机短信确认更换")
    @PostMapping("/smsConfirmationMobileNo")
    public Empty smsConfirmationMobileNo(@RequestBody @Valid SMSChangeMobileNoRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserBasicController.SMSConfirmationMobileNo requestVO={}, userId={}", JSON.toJSONString(requestVO), userId);

        if (StringUtils.isBlank(requestVO.getMobileNo()) || !ParameterValidator.isMobileNo(requestVO.getMobileNo())) {
            throw new BizException(LoginAccountErrorCode.LOGIN_MOBILENO_FORMAT_ERROR);
        }
        if(!MobileChangeRecordEnum.ChangeTypeEnum.REAL_NAME_CHANGE.getValue().equals(requestVO.getType())
                && !MobileChangeRecordEnum.ChangeTypeEnum.SMS_CHANGE.getValue().equals(requestVO.getType())){
            throw new BizException("USR10035");
        }

        SMSChangeMobileNoRequestDTO requestDTO = new SMSChangeMobileNoRequestDTO();
        requestDTO.setUserId(userId);
        requestDTO.setSmsCode(requestVO.getSmsCode());
        requestDTO.setType(requestVO.getType());
        requestDTO.setMobileNo(privacyMasks.encryptPrivacy(requestVO.getMobileNo()));
        mobileChangeRecordDubboService.smsConfirmationMobileNo(requestDTO);

        return Empty.getInstance();
    }

    @AuthIgnore
    @PostMapping("myPageGuideLanguage")
    @ApiOperation("我的页面引导语(黄敏)")
    public Result<MyPageGuideLanguageResponseVO> myPageGuideLanguage() {
        MyPageGuideLanguageResponseVO responseVO = new MyPageGuideLanguageResponseVO();
        List<TradeConfigEnum> enumList = new ArrayList<>();
        enumList.add(TradeConfigEnum.SLOGAN_MAIN_COPYWRITING);             // 引导语.主文案
        enumList.add(TradeConfigEnum.SLOGAN_SECONDARY_COPYWRITING);        // 引导语.副文案

        Map<String, String> tradeConfig = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
        if (!CollectionUtils.isEmpty(tradeConfig)) {
            if(StringUtils.isNotBlank(tradeConfig.get(TradeConfigEnum.SLOGAN_MAIN_COPYWRITING.getConfigKey()))){
                responseVO.setMasterGuideLanguage(tradeConfig.get(TradeConfigEnum.SLOGAN_MAIN_COPYWRITING.getConfigKey()));
            }
            if(StringUtils.isNotBlank(tradeConfig.get(TradeConfigEnum.SLOGAN_SECONDARY_COPYWRITING.getConfigKey()))){
                responseVO.setDeputyGuideLanguage(tradeConfig.get(TradeConfigEnum.SLOGAN_SECONDARY_COPYWRITING.getConfigKey()));
            }
        }
        return Result.with(responseVO);
    }

    /**
     * 验证第三方TOKEN，获取userId
     * @param token
     * @param channel
     * @return
     */
    private String validThirdToken(String token, Integer channel) {
        String userId;
        if (channel == null) {
            userId = r360RedisService.verifyTokenAndGetUserId(token);
        } else {
            userId = r360RedisService.verifyTokenAndGetUserId(token, channel);
        }
        return userId;
    }

    /**
     * 获取orgId
     * @param channel
     * @param orgCode
     * @return
     */
    private String getOrgId(Integer channel, String orgCode) {
        String orgId = OrgConstant.NIIWOO_ORG_ID;

        if (Objects.equals(R360RedisService.ThirdPart.ORG.getChannel(), channel)) {
            orgId = organizationDubboService.loadValidOrgId(orgCode);
        }

        return orgId;
    }

}
